﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using bg;

namespace four
{
  public class FourMove : GameMove
  {
    public int i { get; set; }

    public int player { get; set; }
  }

  public class Four : GameState
  {
    public Four(int w, int h)
    {
      this.w = w;
      this.h = h;
      board = Enumerable.Repeat(0, w * h).ToList();
      player = 1;
    }

    public Four(Four four, FourMove move)
    {
      w = four.w;
      h = four.h;
      board = new List<int>(four.board);
      Set(move.i,h - 1 - ColHeight(move.i), move.player);
      player = OtherPlayer(four.player);
    }

    private int Get(int i, int j)
    {
      return board[j * w + i];
    }

    private void Set(int i, int j, int val)
    {
      board[j * w + i] = val;
    }

    private int ColHeight(int i)
    {
      int j;
      for (j = 0; j < h && Get(i, h - 1 - j) != 0; ++j) ;
      return j;
    }

    private static int OtherPlayer(int player)
    {
      return player == 1 ? 2 : 1;
    }

    private int CountLines(int length, int count, int player)
    {
      int lines = 0;
      for (int i = 0; i < w; ++i)
      {
        for (int j = 0; j < h; ++j)
        {
          for (int di = -1; di <= 1; ++di)
          {
            for (int dj = -1; dj <= 1; ++dj)
            {
              int maxi = i + di * (length - 1);
              int maxj = j + dj * (length - 1);
              if ((di != 0 || dj != 0) && maxi >= 0 && maxi < w && maxj >= 0 && maxj < h)
              {
                int match = 0;
                int other = 0;
                for (int k = 0; k < length; ++k)
                {
                  int val = Get(i + di * k, j + dj * k);
                  if (val == player)
                  {
                    ++match;
                  }
                  else if (val != 0)
                  {
                    ++other;
                  }
                }
                if (match == count && other == 0)
                {
                  ++lines;
                }
              }
            }
          }
        }
      }
      return lines;
    }

    private int w;

    private int h;

    private IList<int> board;

    private int player;

    public IList<GameMove> Expand()
    {
      IList<GameMove> moves = new List<GameMove>();
      for (int i = 0; i < w; ++i)
      {
        if (ColHeight(i) < h)
        {
          moves.Add(new FourMove() { i = i, player = player });
        }
      }
      return moves;
    }

    public GameState Apply(GameMove move)
    {
      System.Diagnostics.Debug.Assert(move is FourMove);
      return new Four(this, move as FourMove);
    }

    public float Eval(int player)
    {
      float score = 0;
      for (int p = 1; p <= 2; ++p)
      {
        for (int i = 0; i < 4; ++i)
        {
          score += (float)Math.Pow(10, i + 1) * CountLines(4, i, p) * (p == player ? 1 : -1);
        }
      }
      return score;
    }

    public int GetWinner()
    {
      for (int player = 1; player <= 2; ++player)
      {
        if (CountLines(4, 4, player) > 0)
        {
          return player;
        }
      }
      if (board.All(val => val != 0))
      {
        return -1;
      }
      return 0;
    }

    public int GetPlayer()
    {
      return player;
    }

    public override string ToString()
    {
      string s = "";
      for (int j = 0; j < h; ++j)
      {
        for (int i = 0; i < w; ++i)
        {
          s += Get(i, j);
          if (i < w - 1)
          {
            s += "|";
          }
        }
        s += "\n";
      }
      s += string.Concat(Enumerable.Repeat("-+", w - 1)) + "-\n";
      return s;
    }
  }
}
